package scaladuct

import collection.immutable.List
import java.lang.String
import org.apache.commons.convert.{Converter, Converters}

/**
 * <p>
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: Aug 7, 2010
 * Time: 11:11:30 AM
 */
trait CookieBeanModerator[X] extends Function[ConfigPage[X], AnyRef] {
  val failFast: Boolean

  def apply(page: ConfigPage[X]): AnyRef = {
    apply(ConfigPageTO(page), page.getCookie)
  }

  def apply(pageTO: ConfigPageTO, cookie: AnyRef): AnyRef = {
    if (cookie == Terminal)
      Terminal
    else {
      val cookieBean = CookieBeanFactory(cookie)
      moderate(pageTO, cookieBean).cookie
    }
  }

  def close() {
    println("Closing command line moderator")
  }

  protected def moderate(pageTO: ConfigPageTO, cookieBean: CookieBean[AnyRef]): CookieBean[AnyRef] = null

  protected def printMessage(message: AnyRef) {}

  protected def printErrorMessage(message: AnyRef) {}
}

trait CommandLineModerator[X] extends CookieBeanModerator[X] {
  override protected def moderate(pageTO: ConfigPageTO, cookieBean: CookieBean[AnyRef]): CookieBean[AnyRef] = {
    val origProps: List[PropertyValue[AnyRef]] = cookieBean.props
    processHeader(pageTO, cookieBean)
    val updatedProps = update(pageTO, origProps)
    val updatedCookieBean: CookieBean[AnyRef] = cookieBean.update(updatedProps)
    processFooter(pageTO, cookieBean)

    updatedCookieBean
  }

  private def update(pageTO: ConfigPageTO, props: List[PropertyValue[AnyRef]]): List[PropertyValue[AnyRef]] = {
    props match {
      case List() => List()
      case prop :: remaining => {
        val updated: PropertyValue[AnyRef] = updateProperty(pageTO, prop)
        updated :: update(pageTO, remaining)
      }
    }
  }

  protected def updateProperty(pageTO: ConfigPageTO, prop: PropertyValue[AnyRef]): PropertyValue[AnyRef] = {
    val response = try {
      collectNewValue(pageTO, prop)
    } catch {
      case e: Exception if (!failFast) => {
        printErrorMessage(e)
        collectNewValue(pageTO, prop)
      }
    }
    if (response != "") {
      val converter = Converters.getConverter(classOf[String], prop.clazz);
      val converted: AnyRef = converter.convert(response).asInstanceOf[AnyRef]
      val updated: PropertyValue[AnyRef] = prop.update(converted);
      updated
    } else
      prop
  }

  protected def collectNewValue(pageTO: ConfigPageTO, prop: PropertyValue[AnyRef]): String

  protected def processHeader(pageTO: ConfigPageTO, cookieBean: CookieBean[AnyRef]) {}

  protected def processFooter(pageTO: ConfigPageTO, cookieBean: CookieBean[AnyRef]) {}
}

class ConsoleModerator[X](noCorrections: Boolean) extends CommandLineModerator[X] {
  val failFast = noCorrections

  def this() = this (false)

  protected def collectNewValue(pageTO: ConfigPageTO, prop: PropertyValue[AnyRef]) = {
    val presetValue = try {
      val converterToString: Converter[AnyRef, String] =
      Converters.getConverter(prop.clazz.asInstanceOf[Class[AnyRef]], classOf[String])
      converterToString.convert(prop.value)
    } catch {
      case e: Exception => ""
    }

    val prompt: String = prop.name + "(" + prop.clazz.getName + ") [" + presetValue + "]>"
    print(prompt)
    readLine
  }

  override protected def processHeader(pageTO: ConfigPageTO, cookieBean: CookieBean[AnyRef]) {
    println("*** Page " + pageTO.pageId)
  }

  override protected def processFooter(pageTO: ConfigPageTO, cookieBean: CookieBean[AnyRef]) {
    //println("***")
  }

  override protected def printMessage(message: AnyRef) {
    println(message)
  }

  override protected def printErrorMessage(message: AnyRef) {
    System.err.println(message)
  }

}